package com.fangda.network.websocket.server;

import com.fangda.network.NetworkConfig;
import com.fangda.network.NetworkMessage;
import com.fangda.network.NetworkMessageCallback;
import com.fangda.network.NetworkType;
import com.fangda.network.websocket.AbstractWebsocketNetwork;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.ServerWebSocket;
import io.vertx.ext.web.Router;
import lombok.Getter;
import lombok.Setter;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class WebsocketServerNetwork extends AbstractWebsocketNetwork {

    @Setter
    @Getter
    private HttpServer server;

    @Setter
    @Getter
    private Router router;

    public final static List<ServerWebSocket> SESSIONS = new CopyOnWriteArrayList<>();

    public WebsocketServerNetwork(String id, NetworkConfig config) {
        super(id, config);
    }

    public void startup() {
        router.route(config.getPath()).handler(rct -> {
            rct.response().end("success");
        });
        server.webSocketHandler(ws -> {//客户端连接成功回调此方法
            SESSIONS.add(ws);
            if(callback != null) {
                callback.connectionChange(true, null);
            }
            initWebSocket(ws);
        });

        server.requestHandler(router).listen(config.getPort(), config.getIp(), result -> {
            setAlive(result.succeeded());
            if(callback != null) {
                callback.connectionChange(result.succeeded(), null);
            }
        });

    }

    @Override
    public NetworkType getNetworkType() {
        return NetworkType.WEBSOCKET_SERVER;
    }

    @Override
    public void shutdown() {
        if(server != null) {
            server.close(r -> {
                setAlive(!r.succeeded());
                SESSIONS.clear();
                if(callback != null) {
                    callback.connectionChange(false, null);
                }
            });
        } else {
            this.setAlive(false);
            SESSIONS.clear();
        }

    }

    @Override
    public void reload() {
        shutdown();
        startup();
    }

    private void initWebSocket(ServerWebSocket websocket) {

        websocket.handler(r -> {//收数据
            if(config.getParser() != null) {
                config.getParser().decode(new NetworkMessage(r.getBytes(), websocket.remoteAddress().toString()));
            }
        });
        websocket.closeHandler( r -> {//关闭数据
            SESSIONS.remove(websocket);
            if(callback != null) {
                callback.connectionChange(false, null);
            }
        });
        websocket.exceptionHandler(v -> {
            if(getCallback() != null) {
                getCallback().exceptionHandler(v);
            }
        });
    }

    public List<ServerWebSocket> getSessions() {
        return SESSIONS;
    }

    public void send(NetworkMessage message, NetworkMessageCallback messageCallback) {
        for(ServerWebSocket webSocket : SESSIONS) {
            if(webSocket.isClosed()) {
                continue;
            }
            webSocket.writeBinaryMessage(Buffer.buffer(message.getPayload()), r -> {
                if(messageCallback != null) {
                    messageCallback.callback(r, webSocket.remoteAddress());
                }
            });
        }
    }

    public void send(NetworkMessage message, NetworkMessageCallback messageCallback, List<ServerWebSocket> sessions) {
        for(ServerWebSocket webSocket : SESSIONS) {
            if(webSocket.isClosed()) {
                continue;
            }
            if(!sessions.contains(webSocket)) {
                continue;
            }
            webSocket.writeBinaryMessage(Buffer.buffer(message.getPayload()), r -> {
                if(messageCallback != null) {
                    messageCallback.callback(r, webSocket.remoteAddress());
                }
            });
        }
    }
}
